package com.colin.juc.flowcontrol.condition;

import java.util.PriorityQueue;
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by Colin on 2020/5/31 12:50
 * email: colinzhaodong@gmail.com
 * desc: 演示生产者消费者模式
 *
 * @author zhaod
 */
public class ConditionDemo2 {
	private int queueSize = 10;
	private BlockingQueue<Integer> queue = new ArrayBlockingQueue<>(queueSize,true);
	private final Lock lock = new ReentrantLock();
	private final Condition notFull = lock.newCondition();
	private final Condition notEmpty = lock.newCondition();

	class Consumer implements Runnable {

		@Override
		public void run() {
			consume();
		}

		private void consume() {
			while (true) {
				lock.lock();
				try {
					while (queue.size() == 0) {
						System.out.println("队列空，等待数据");
						try {
							notEmpty.await();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					queue.poll();
					notFull.signalAll();
					System.out.println("从队列里取走了一个数据，队列剩余" + queue.size() + "个元素");
				} finally {
					lock.unlock();
				}
			}
		}
	}

	class Producer implements Runnable {

		@Override
		public void run() {
			producer();
		}

		private void producer() {
			while (true) {
				lock.lock();
				try {
					while (queue.size() == queueSize) {
						System.out.println("队列满，等待取数据");
						try {
							notFull.await();
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
					queue.offer(1);
					notEmpty.signalAll();
					System.out.println("向队列插入了一个元素，队列剩余空间" + (queueSize - queue.size()));
				} finally {
					lock.unlock();
				}
			}
		}
	}

	public static void main(String[] args) {
		ConditionDemo2 conditionDemo2 = new ConditionDemo2();
		Producer producer = conditionDemo2.new Producer();
		Consumer consumer = conditionDemo2.new Consumer();
		new Thread(producer).start();
		new Thread(consumer).start();
	}
}
